<template>
  <view
    v-show="url"
    :mode="modeValue"
    :change:mode="mwx.changeMode"
    :rotate="rotate"
    :change:rotate="mwx.changeRotate"
  >
    <!-- #ifdef MP-WEIXIN -->
    <canvas
      type="2d"
      class="canvas"
      :style="{ width: target.width + 'px', height: target.height + 'px' }"
    ></canvas>
    <!-- #endif -->
    <!-- #ifdef APP-PLUS || H5 -->
    <canvas
      :canvas-id="canvasId"
      :style="{ width: target.width + 'px', height: target.height + 'px' }"
    ></canvas>
    <!-- #endif -->
    <view class="panel">
      <view
        class="body"
        @touchstart="mwx.touchstart"
        @touchmove="mwx.touchmove"
        @touchend="mwx.touchend"
        @touchcancel="mwx.touchcancel"
      >
        <view
          class="image-wrap"
          :class="{ transit: transit }"
          :change:rect="mwx.changeImage"
          :rect="image"
        >
          <image
            class="image"
            :class="{ transit: transit }"
            :src="url"
            @load="imageLoad"
          />
        </view>
        <view class="mask"></view>
        <view
          class="frame"
          :class="{ transit: transit }"
          :change:rect="mwx.changeFrame"
          :rect="frame"
        >
          <view class="rect">
            <view class="image-rect" :class="{ transit: transit }">
              <image class="image" :class="{ transit: transit }" :src="url" />
            </view>
          </view>
          <view class="line-one"></view>
          <view class="line-two"></view>
          <view class="line-three"></view>
          <view class="line-four"></view>
          <view class="frame-left-top" @touchstart="mwx.touchstart"></view>
          <view class="frame-left-bottom" @touchstart="mwx.touchstart"></view>
          <view class="frame-right-top" @touchstart="mwx.touchstart"></view>
          <view class="frame-right-bottom" @touchstart="mwx.touchstart"></view>
        </view>
      </view>
      <view class="toolbar">
        <view @tap="oncancle" class="btn-cancel">取消</view>
        <view @tap="rotateAngle" class="btn-rotate">旋转</view>
        <view @tap="onok" class="btn-ok">确定</view>
      </view>
    </view>
  </view>
</template>
<script>
  /**
   * @property {String} mode 模式
   *  @value fixed 固定模式，裁剪出固定大小
   *  @value ratio 等比模式，宽高等比缩放
   *  @value free 自由模式，不限制宽高比
   * @property {String} url 图片路径
   * @property {Number} width 宽度
   * @property {Number} height 高度
   * @property {Number} maxWidth 最大宽带
   * @property {Number} minHeight 最大高度
   */
  export default {
    props: {
      mode: {
        type: String,
        default: 'free',
      },
      url: {
        type: String,
        default: '',
      },
      width: {
        type: Number,
        default: 200,
      },
      height: {
        type: Number,
        default: 200,
      },
      maxWidth: {
        type: Number,
        default: 1024,
      },
      maxHeight: {
        type: Number,
        default: 1024,
      },
    },
    data() {
      return {
        canvasId: Math.random().toString(36).slice(-6),
        real: {
          width: 100,
          height: 100,
        },
        target: {
          width: 100,
          height: 100,
        },
        body: {
          width: 100,
          height: 100,
        },
        frame: {
          left: 50,
          top: 50,
          width: 200,
          height: 300,
        },
        image: {
          left: 20,
          top: 20,
          width: 300,
          height: 400,
        },
        rotate: 0,
        transit: false,
        modeValue: '',
      };
    },
    methods: {
      imageLoad(event) {
        uni.getImageInfo({
          src: this.url,
          success: rst => {
            this.real.width = rst.width;
            this.real.height = rst.height;
            this.target = {};
            let query = uni.createSelectorQuery().in(this);
            query
              .select('.body')
              .boundingClientRect(data => {
                this.body.width = data.width;
                this.body.height = data.height;
                this.init();
              })
              .exec();
          },
        });
      },
      init() {
        this.modeValue = this.mode;
        this.rotate = 0;
        let rate = this.width / this.height;
        let width = this.body.width * 0.7;
        let height = this.body.height * 0.7;
        if (width / height > rate) {
          width = height * rate;
        } else {
          height = width / rate;
        }
        let left = (this.body.width - width) / 2;
        let top = (this.body.height - height) / 2;
        this.frame = {
          left: left,
          top: top,
          width: width,
          height: height,
        };
        rate = this.real.width / this.real.height;
        width = this.frame.width;
        height = this.frame.height;
        if (width / height > rate) {
          height = width / rate;
        } else {
          width = height * rate;
        }
        left = (this.frame.width - width) / 2 + this.frame.left;
        top = (this.frame.height - height) / 2 + this.frame.top;
        this.image = {
          left: left,
          top: top,
          width: width,
          height: height,
        };
      },
      async updateData(data) {
        this.frame = data.frame;
        this.image = data.image;
        await this.$nextTick();
        this.trimImage();
      },
      trimImage() {
        let rate = this.frame.width / this.frame.height;
        let width = this.body.width * 0.7;
        let height = this.body.height * 0.7;
        if (width / height > rate) {
          width = height * rate;
        } else {
          height = width / rate;
        }
        let left = (this.body.width - width) / 2;
        let top = (this.body.height - height) / 2;
        let mul = width / this.frame.width;
        let ox = this.frame.left - this.image.left;
        let oy = this.frame.top - this.image.top;
        this.frame = {
          left: left,
          top: top,
          width: width,
          height: height,
        };
        width = this.image.width * mul;
        height = this.image.height * mul;
        left = this.frame.left - ox * mul;
        top = this.frame.top - oy * mul;
        this.image = {
          left: left,
          top: top,
          width: width,
          height: height,
        };
        if (mul != 1) {
          this.transit = true;
          setTimeout(() => {
            this.transit = false;
          }, 300);
        }
      },
      rotateAngle() {
        this.rotate -= 90;
        let width = this.image.height;
        let height = this.image.width;
        let left = this.image.left;
        let top = this.image.top;
        let rate = width / height;
        if (width < this.frame.width) {
          width = this.frame.width;
          height = width / rate;
        }
        if (height < this.frame.height) {
          height = this.frame.height;
          width = height * rate;
        }
        if (left > this.frame.left) {
          left = this.frame.left;
        }
        if (top > this.frame.top) {
          top = this.frame.top;
        }
        if (left + width < this.frame.left + this.frame.width) {
          left = this.frame.left + this.frame.width - width;
        }
        if (top + height < this.frame.top + this.frame.height) {
          top = this.frame.top + this.frame.height - height;
        }
        this.image = {
          left: left,
          top: top,
          width: width,
          height: height,
        };
        this.transit = true;
        setTimeout(() => {
          this.transit = false;
        }, 300);
      },
      onok() {
        // #ifdef MP-WEIXIN
        this.cropWx();
        // #endif
        // #ifdef APP-PLUS || H5
        this.cropAppH5();
        // #endif
      },
      oncancle() {
        this.$emit('cancel');
      },
      async cropWx() {
        let mx = this.computeMatrix();
        this.target = {
          width: mx.tw,
          height: mx.th,
        };
        let canvas = await new Promise(resolve => {
          uni
            .createSelectorQuery()
            .in(this)
            .select('.canvas')
            .fields({ node: true })
            .exec(rst => {
              let node = rst[0].node;
              resolve(node);
            });
        });
        canvas.width = mx.tw;
        canvas.height = mx.th;
        uni.showLoading({
          title: '处理中',
        });
        await new Promise(resolve => {
          setTimeout(resolve, 200);
        });
        let context = canvas.getContext('2d');
        let image = canvas.createImage();
        await new Promise((resolve, reject) => {
          image.onload = resolve;
          image.onerror = reject;
          image.src = this.url;
        });
        context.save();
        context.rotate((this.rotate * Math.PI) / 180);
        context.drawImage(
          image,
          mx.sx,
          mx.sy,
          mx.sw,
          mx.sh,
          mx.dx,
          mx.dy,
          mx.dw,
          mx.dh,
        );
        context.restore();
        wx.canvasToTempFilePath({
          canvas: canvas,
          destWidth: mx.tw,
          destHeight: mx.th,
          success: rst => {
            let path = rst.tempFilePath;
            this.$emit('ok', {
              path: path,
            });
          },
          complete: () => {
            uni.hideLoading();
          },
        });
      },
      async cropAppH5() {
        let mx = this.computeMatrix();
        this.target = {
          width: mx.tw,
          height: mx.th,
        };
        uni.showLoading({
          title: '处理中',
        });
        await new Promise(resolve => {
          setTimeout(resolve, 200);
        });
        let context = uni.createCanvasContext(this.canvasId, this);
        context.save();
        context.rotate((this.rotate * Math.PI) / 180);
        context.drawImage(
          this.url,
          mx.sx,
          mx.sy,
          mx.sw,
          mx.sh,
          mx.dx,
          mx.dy,
          mx.dw,
          mx.dh,
        );
        context.restore();
        await new Promise(resolve => {
          context.draw(false, resolve);
        });
        uni.canvasToTempFilePath(
          {
            canvasId: this.canvasId,
            destWidth: mx.tw,
            destHeight: mx.th,
            success: rst => {
              let path = rst.tempFilePath;
              // #ifdef H5
              let base64 = path;
              path = this.parseBlob(path);
              this.$emit('ok', {
                path: path,
                base64: base64,
              });
              // #endif
              // #ifdef APP-PLUS
              this.$emit('ok', {
                path: path,
              });
              // #endif
            },
            complete: () => {
              uni.hideLoading();
            },
          },
          this,
        );
      },
      computeMatrix() {
        let width = this.width;
        let height = this.height;
        let mul = this.image.width / this.real.width;
        if (this.rotate % 180 != 0) {
          mul = this.image.height / this.real.width;
        }
        if (this.mode != 'fixed') {
          width = this.frame.width / mul;
          height = this.frame.height / mul;
        }
        let rate = width / height;
        if (width > this.maxWidth) {
          width = this.maxWidth;
          height = width / rate;
        }
        if (height > this.maxHeight) {
          height = this.maxHeight;
          width = height * rate;
        }
        let sx = (this.frame.left - this.image.left) / mul;
        let sy = (this.frame.top - this.image.top) / mul;
        let sw = this.frame.width / mul;
        let sh = this.frame.height / mul;
        let ox = sx + sw / 2;
        let oy = sy + sh / 2;
        if (this.rotate % 180 != 0) {
          let temp = sw;
          sw = sh;
          sh = temp;
        }
        let angle = this.rotate % 360;
        if (angle < 0) {
          angle += 360;
        }
        if (angle == 270) {
          var x = this.real.width - oy;
          var y = ox;
          ox = x;
          oy = y;
        }
        if (angle == 180) {
          var x = this.real.width - ox;
          var y = this.real.height - oy;
          ox = x;
          oy = y;
        }
        if (angle == 90) {
          var x = oy;
          var y = this.real.height - ox;
          ox = x;
          oy = y;
        }
        sx = ox - sw / 2;
        sy = oy - sh / 2;
        let dr = { x: 0, y: 0, w: width, h: height };
        dr = this.parseRect(dr, -this.rotate);
        return {
          tw: width,
          th: height,
          sx: sx,
          sy: sy,
          sw: sw,
          sh: sh,
          dx: dr.x,
          dy: dr.y,
          dw: dr.w,
          dh: dr.h,
        };
      },
      parsePoint(point, angle) {
        let result = {};
        result.x =
          point.x * Math.cos((angle * Math.PI) / 180) -
          point.y * Math.sin((angle * Math.PI) / 180);
        result.y =
          point.y * Math.cos((angle * Math.PI) / 180) +
          point.x * Math.sin((angle * Math.PI) / 180);
        return result;
      },
      parseRect(rect, angle) {
        let x1 = rect.x;
        let y1 = rect.y;
        let x2 = rect.x + rect.w;
        let y2 = rect.y + rect.h;
        let p1 = this.parsePoint({ x: x1, y: y1 }, angle);
        let p2 = this.parsePoint({ x: x2, y: y2 }, angle);
        let result = {};
        result.x = Math.min(p1.x, p2.x);
        result.y = Math.min(p1.y, p2.y);
        result.w = Math.abs(p2.x - p1.x);
        result.h = Math.abs(p2.y - p1.y);
        return result;
      },
      parseBlob(base64) {
        let arr = base64.split(',');
        let mime = arr[0].match(/:(.*?);/)[1];
        let bstr = atob(arr[1]);
        let n = bstr.length;
        let u8arr = new Uint8Array(n);
        for (let i = 0; i < n; i++) {
          u8arr[i] = bstr.charCodeAt(i);
        }
        let url = URL || webkitURL;
        return url.createObjectURL(new Blob([u8arr], { type: mime }));
      },
    },
  };
</script>

<script module="mwx" lang="wxs">
  var mode = "";
  var rotate = 0;
  var image = {
  	left: 0,
  	top: 0,
  	width: 0,
  	height: 0
  };
  var frame = {
  	left: 0,
  	top: 0,
  	width: 0,
  	height: 0
  };
  var touches = [];
  var touchType = "";
  var start = {
  	frame: {
  		left: 0,
  		top: 0,
  		width: 0,
  		height: 0
  	},
  	image: {
  		left: 0,
  		top: 0,
  		width: 0,
  		height: 0
  	}
  };
  function changeMode(value) {
  	mode = value;
  }
  function changeRotate(value, old, oi, instance) {
  	rotate = value;
  	delayUpdateStyle(oi);
  }
  function changeImage(value, old, oi, instance) {
  	image = value;
  	delayUpdateStyle(oi);
  }
  function changeFrame(value, old, oi, instance) {
  	frame = value;
  	delayUpdateStyle(oi);
  }
     function delayUpdateStyle(oi) {
         // #ifdef APP-PLUS || H5
         setTimeout(() => {
             updateStyle(oi);
         });
         // #endif
         // #ifdef MP-WEIXIN
         updateStyle(oi);
         // #endif
     }
  function touchstart(event, oi) {
  	// #ifdef APP-PLUS || H5
  	// event.preventDefault();
  	// event.stopPropagation();
  	// #endif
  	touches = event.touches;
  	var instance = event.instance;
  	if (instance.hasClass("body")) {
  		touchType = "body";
  	} else if (instance.hasClass("frame-left-top")) {
  		touchType = "left-top";
  	} else if (instance.hasClass("frame-left-bottom")) {
  		touchType = "left-bottom";
  	} else if (instance.hasClass("frame-right-top")) {
  		touchType = "right-top";
  	} else if (instance.hasClass("frame-right-bottom")) {
  		touchType = "right-bottom";
  	}
  	start.frame.left = frame.left;
  	start.frame.top = frame.top;
  	start.frame.width = frame.width;
  	start.frame.height = frame.height;
  	start.image.left = image.left;
  	start.image.top = image.top;
  	start.image.width = image.width;
  	start.image.height = image.height;
  	return false;
  }
  function touchmove(event, oi) {
  	// #ifdef APP-PLUS || H5
  	// event.preventDefault();
  	// event.stopPropagation();
  	// #endif
  	var instance = event.instance;
  	if (touches.length == 1) {
  		if (touchType == "body") {
  			moveImage(touches[0], event.touches[0], oi);
  		} else {
  			scaleFrame(touches[0], event.touches[0], oi);
  		}
  	} else if (touches.length == 2 && event.touches.length == 2) {
  		var ta = touches[0];
  		var tb = touches[1];
  		var tc = event.touches[0];
  		var td = event.touches[1];
  		if (ta.identifier != tc.identifier) {
  			var temp = tc;
  			tc = td;
  			td = temp;
  		}
  		scaleImage(ta, tb, tc, td, oi);
  	}
  }
  function touchend(event, oi) {
  	touches = [];
  	oi.callMethod("updateData", {frame: frame, image: image});
  }
  function touchcancel(event, oi) {
  	touches = [];
  	oi.callMethod("updateData", {frame: frame, image: image});
  }
  function moveImage(ta, tb, oi) {
  	var ax = tb.clientX - ta.clientX;
  	var ay = tb.clientY - ta.clientY;
  	image.left = start.image.left + ax;
  	image.top = start.image.top + ay;
  	var left = frame.left;
  	var top = frame.top;
  	var width = frame.width;
  	var height = frame.height;
  	if (image.left > left) {
  		image.left = left;
  	}
  	if (image.top > top) {
  		image.top = top;
  	}
  	if (image.left + image.width < left + width) {
  		image.left = left + width - image.width;
  	}
  	if (image.top + image.height < top + height) {
  		image.top = top + height - image.height;
  	}
  	updateStyle(oi);
  }
  function scaleImage(ta, tb, tc, td, oi) {
  	var x1 = ta.clientX;
  	var y1 = ta.clientY;
  	var x2 = tb.clientX;
  	var y2 = tb.clientY;
  	var x3 = tc.clientX;
  	var y3 = tc.clientY;
  	var x4 = td.clientX;
  	var y4 = td.clientY;
  	var ol = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
  	var el = Math.sqrt((x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4));
  	var ocx = (x1 + x2) / 2;
  	var ocy = (y1 + y2) / 2;
  	var ecx = (x3 + x4) / 2;
  	var ecy = (y3 + y4) / 2;
  	var ax = ecx - ocx;
  	var ay = ecy - ocy;
  	var scale = el / ol;
  	if (start.image.width * scale < frame.width) {
  		scale = frame.width / start.image.width;
  	}
  	if (start.image.height * scale < frame.height) {
  		scale = frame.height / start.image.height;
  	}
  	if (start.image.width * scale < frame.width) {
  		scale = frame.width / start.image.width;
  	}
  	image.left = start.image.left + ax - (ocx - start.image.left) * (scale - 1);
  	image.top = start.image.top + ay - (ocy - start.image.top) * (scale - 1);
  	image.width = start.image.width * scale;
  	image.height = start.image.height * scale;
  	if (image.left > frame.left) {
  		image.left = frame.left;
  	}
  	if (image.top > frame.top) {
  		image.top = frame.top;
  	}
  	if (image.left + image.width < frame.left + frame.width) {
  		image.left = frame.left + frame.width - image.width;
  	}
  	if (image.top + image.height < frame.top + frame.height) {
  		image.top = frame.top + frame.height - image.height;
  	}
  	updateStyle(oi);
  }
  function scaleFrame(ta, tb, oi) {
  	var ax = tb.clientX - ta.clientX;
  	var ay = tb.clientY - ta.clientY;
  	var x1 = start.frame.left;
  	var y1 = start.frame.top;
  	var x2 = start.frame.left + start.frame.width;
  	var y2 = start.frame.top + start.frame.height;
  	var cx1 = false;
  	var cy1 = false;
  	var cx2 = false;
  	var cy2 = false;
  	var mix = 30;
  	var rate = frame.width / frame.height;
  	if (touchType == "left-top") {
  		x1 += ax;
  		y1 += ay;
  		cx1 = true;
  		cy1 = true;
  	} else if (touchType == "left-bottom") {
  		x1 += ax;
  		y2 += ay;
  		cx1 = true;
  		cy2 = true;
  	} else if (touchType == "right-top") {
  		x2 += ax;
  		y1 += ay;
  		cx2 = true;
  		cy1 = true;
  	} else if (touchType == "right-bottom") {
  		x2 += ax;
  		y2 += ay;
  		cx2 = true;
  		cy2 = true;
  	}
  	if (x1 < image.left) {
  		x1 = image.left;
  	}
  	if (y1 < image.top) {
  		y1 = image.top;
  	}
  	if (x2 > image.left + image.width) {
  		x2 = image.left + image.width;
  	}
  	if (y2 > image.top + image.height) {
  		y2 = image.top + image.height;
  	}
  	if (cx1) {
  		if (x1 > x2 - mix) {
  			x1 = x2 - mix;
  		}
  	}
  	if (cy1) {
  		if (y1 > y2 - mix) {
  			y1 = y2 - mix;
  		}
  	}
  	if (cx2) {
  		if (x2 < x1 + mix) {
  			x2 = x1 + mix;
  		}
  	}
  	if (cy2) {
  		if (y2 < y1 + mix) {
  			y2 = y1 + mix;
  		}
  	}
  	if (cx1) {
  		if (mode != "free") {
  			var val = x2 - rate * (y2 - y1);
  			if (x1 < val) {
  				x1 = val;
  			}
  		}
  	}
  	if (cy1) {
  		if (mode != "free") {
  			var val = y2 - (x2 - x1) / rate;
  			if (y1 < val) {
  				y1 = val;
  			}
  		}
  	}
  	if (cx2) {
  		if (mode != "free") {
  			var val = rate * (y2 - y1) + x1;
  			if (x2 > val) {
  				x2 = val;
  			}
  		}
  	}
  	if (cy2) {
  		if (mode != "free") {
  			var val = (x2 - x1) / rate + y1;
  			if (y2 > val) {
  				y2 = val;
  			}
  		}
  	}
  	frame.left = x1;
  	frame.top = y1;
  	frame.width = x2 - x1;
  	frame.height = y2 - y1;
  	updateStyle(oi);
  }
  function updateStyle(oi) {
  	oi.selectComponent(".frame").setStyle({
  		"left": frame.left + "px",
  		"top": frame.top + "px",
  		"width": frame.width + "px",
  		"height": frame.height + "px"
  	});
  	oi.selectComponent(".image-wrap").setStyle({
  		"left": image.left + "px",
  		"top": image.top + "px",
  		"width": image.width + "px",
  		"height": image.height + "px"
  	});
  	oi.selectComponent(".image-rect").setStyle({
  		"left": image.left - frame.left + "px",
  		"top": image.top - frame.top + "px",
  		"width": image.width + "px",
  		"height": image.height + "px"
  	});
  	var left = 0;
  	var top = 0;
  	var width = image.width;
  	var height = image.height;
  	if (rotate % 180 != 0) {
  		width = image.height;
  		height = image.width;
  		top = width / 2 - height / 2;
  		left = height / 2 - width/ 2;
  	}
  	oi.selectComponent(".image-wrap .image").setStyle({
  		"left": left + "px",
  		"top": top + "px",
  		"width": width + "px",
  		"height": height + "px",
  		"transform": "rotate(" + rotate + "deg)"
  	});
  	oi.selectComponent(".image-rect .image").setStyle({
  		"left": left + "px",
  		"top": top + "px",
  		"width": width + "px",
  		"height": height + "px",
  		"transform": "rotate(" + rotate + "deg)"
  	});
  }
  module.exports = {
  	changeMode: changeMode,
  	changeRotate: changeRotate,
  	changeImage: changeImage,
  	changeFrame: changeFrame,
  	touchstart: touchstart,
  	touchmove: touchmove,
  	touchend: touchend,
  	touchcancel: touchcancel
  };
</script>

<style scoped>
  .panel {
    position: fixed;
    width: 100%;
    height: 100%;
    top: 0;
    bottom: 0;
    z-index: 1000;
    overflow: hidden;
  }
  .canvas {
    position: absolute;
    top: 5000px;
    left: 5000px;
  }
  .toolbar {
    position: absolute;
    width: 100%;
    height: 100rpx;
    left: 0rpx;
    bottom: 0rpx;
    display: flex;
    justify-content: space-around;
    align-items: center;
  }
  .btn-cancel {
    font-size: 40rpx;
    color: #d5dfe5;
    font-weight: bold;
  }
  .btn-ok {
    font-size: 40rpx;
    color: #ffffff;
    font-weight: bold;
  }
  .btn-rotate {
    font-size: 40rpx;
    color: #d5dfe5;
    font-weight: bold;
  }
  .body {
    position: absolute;
    left: 0rpx;
    right: 0rpx;
    top: 0rpx;
    bottom: 0rpx;
    background: black;
    overflow: hidden;
  }
  .mask {
    position: absolute;
    left: 0rpx;
    right: 0rpx;
    top: 0rpx;
    bottom: 0rpx;
    background: black;
    opacity: 0.4;
  }
  .plank {
    position: absolute;
    left: 0rpx;
    right: 0rpx;
    top: 0rpx;
    bottom: 0rpx;
  }
  .image-wrap {
    position: absolute;
  }
  .image-rect {
    position: absolute;
  }
  .image {
    position: absolute;
  }
  .frame {
    position: absolute;
    left: 100px;
    top: 100px;
    width: 200px;
    height: 200px;
  }
  .rect {
    position: absolute;
    left: -2px;
    top: -2px;
    width: 100%;
    height: 100%;
    border: 2px solid white;
    overflow: hidden;
    box-sizing: content-box;
  }
  .line-one {
    position: absolute;
    width: 100%;
    height: 1px;
    background: white;
    left: 0;
    top: 33.3%;
    box-sizing: content-box;
  }
  .line-two {
    position: absolute;
    width: 100%;
    height: 1px;
    background: white;
    left: 0;
    top: 66.7%;
    box-sizing: content-box;
  }
  .line-three {
    position: absolute;
    width: 1px;
    height: 100%;
    background: white;
    top: 0;
    left: 33.3%;
    box-sizing: content-box;
  }
  .line-four {
    position: absolute;
    width: 1px;
    height: 100%;
    background: white;
    top: 0;
    left: 66.7%;
    box-sizing: content-box;
  }
  .frame-left-top {
    position: absolute;
    width: 20px;
    height: 20px;
    left: -6px;
    top: -6px;
    border-left: 4px solid red;
    border-top: 4px solid red;
    box-sizing: content-box;
  }
  .frame-left-bottom {
    position: absolute;
    width: 20px;
    height: 20px;
    left: -6px;
    bottom: -6px;
    border-left: 4px solid red;
    border-bottom: 4px solid red;
    box-sizing: content-box;
  }
  .frame-right-top {
    position: absolute;
    width: 20px;
    height: 20px;
    right: -6px;
    top: -6px;
    border-right: 4px solid red;
    border-top: 4px solid red;
    box-sizing: content-box;
  }
  .frame-right-bottom {
    position: absolute;
    width: 20px;
    height: 20px;
    right: -6px;
    bottom: -6px;
    border-right: 4px solid red;
    border-bottom: 4px solid red;
    box-sizing: content-box;
  }
  .transit {
    transition: width 0.3s, height 0.3s, left 0.3s, top 0.3s, transform 0.3s;
  }
</style>
